# -*- coding: utf_8 -*-
# @Time : 2021/9/22 0022 15:36
# @Author : lyw
# @Remark : 定时缓存
import threading
import time
from itertools import count as _count
import collections
from typing import Any, NoReturn
from copy import deepcopy

_counter = _count().__next__
_counter()  # Consume 0 so first non-main thread has id 1.


def _newname(template="Cache-%d"):
    return template % _counter()


class MiniCache:

    def __init__(self, count_int: int = 128, name_str=None):
        self._name = str(name_str or _newname())
        self.count = count_int
        self.__cache_dict = collections.OrderedDict()
        self.__overtime_dict = {}
        self.lock = threading.RLock()

    def __getitem__(self, item):
        result = self.get(item)
        if result is None:
            raise KeyError("属性不存在")
        return result

    def get(self, key: Any, default=None) -> Any:
        try:
            # self.__cache_dict.get(key)
            overtime = self.__overtime_dict.get(key)
            if overtime is None:
                return default
            else:
                if overtime >= time.time():
                    return deepcopy(self.__cache_dict.get(key, default))
                else:
                    self.delete(key)
                    return default
        except KeyError:
            return default

    def delete(self, key: Any) -> NoReturn:
        try:
            del self.__cache_dict[key]
        except KeyError:
            pass
        try:
            del self.__overtime_dict[key]
        except KeyError:
            pass

    def set(self, key: Any, value: Any, overtime_int: int, cover=True) -> Any:
        """

        @param key:
        @param value:
        @param overtime_int:
        @param cover: 是否覆盖 true 覆盖
        @return:
        """
        blocking = True
        if key not in self.__cache_dict:
            blocking = False
        self.lock.acquire(blocking=blocking)
        if len(self.__cache_dict) >= self.count:
            self.delete(self.__cache_dict.popitem(False)[0])
        if cover:
            set_result = self.__set(key, value, overtime_int)
        else:
            set_result = self.__set(key, self.get(key), overtime_int) if self.get(key) else self.__set(key, value,
                                                                                                       overtime_int)

        self.lock.release()
        return set_result

    def __set(self, key: Any, value: Any, overtime_int: int):

        self.__cache_dict[key] = value
        self.__overtime_dict[key] = time.time() + overtime_int

        return value

    def __repr__(self) -> str:
        """
        打印缓存情况
        @return:
        """
        cd = self.__cache_dict
        return f"%s(size=%s,margin=%s,%s)" % (self._name,
                                              self.count,
                                              (self.count - len(cd)),
                                              [key for key in cd.keys()])

    def __len__(self) -> int:
        """
        返回长度
        @return:
        """
        return len(self.__cache_dict)


if __name__ == '__main__':
    cache = MiniCache()


    def test(j):
        # if j == 1:
        #     time.sleep(10)
        cache.set("1", j, 10)


    for i in range(2):
        t = threading.Thread(target=test, args=(i,))
        t.start()
    for i in range(20):
        time.sleep(1)
